#pragma once

#include <WTypes.h>
#include "base/Lock.h"

namespace xBase
{

    class CTimeDelta;
    class CTime;
    class CTimeTicks;

    // CTimeDelta ------------------------------------------------------------------

    class CTimeDelta
    {
    public:
        CTimeDelta() : m_nDeltaMicroSecs(0)
        {
        }

        // Converts units of time to CTimeDeltas.
        static CTimeDelta FromDays(INT64 nDays);
        static CTimeDelta FromHours(INT64 nHours);
        static CTimeDelta FromMinutes(INT64 nMinutes);
        static CTimeDelta FromSeconds(INT64 nSecs);
        static CTimeDelta FromMilliseconds(INT64 nMS);
        static CTimeDelta FromMicroseconds(INT64 nUS);

        // Returns the internal numeric value of the CTimeDelta object. Please don't
        // use this and do arithmetic on it, as it is more error prone than using the
        // provided operators.
        INT64 ToInternalValue() const
        {
            return m_nDeltaMicroSecs;
        }

        // Returns the time delta in some unit.
        INT InDays() const;
        INT InHours() const;
        INT InMinutes() const;
        DOUBLE InSecondsF() const;
        INT64 InSeconds() const;
        DOUBLE InMillisecondsF() const;
        INT64 InMilliseconds() const;
        INT64 InMillisecondsRoundedUp() const;
        INT64 InMicroseconds() const;

        CTimeDelta& operator=(CTimeDelta Other) 
        {
            m_nDeltaMicroSecs = Other.m_nDeltaMicroSecs;
            return *this;
        }

        // Computations with Other deltas.
        CTimeDelta operator+(CTimeDelta Other) const
        {
            return CTimeDelta(m_nDeltaMicroSecs + Other.m_nDeltaMicroSecs);
        }
        CTimeDelta operator-(CTimeDelta Other) const 
        {
            return CTimeDelta(m_nDeltaMicroSecs - Other.m_nDeltaMicroSecs);
        }

        CTimeDelta& operator+=(CTimeDelta Other)
        {
            m_nDeltaMicroSecs += Other.m_nDeltaMicroSecs;
            return *this;
        }
        CTimeDelta& operator-=(CTimeDelta Other) 
        {
            m_nDeltaMicroSecs -= Other.m_nDeltaMicroSecs;
            return *this;
        }
        CTimeDelta operator-() const 
        {
            return CTimeDelta(-m_nDeltaMicroSecs);
        }

        // Computations with int
        CTimeDelta operator*(INT64 n) const 
        {
            return CTimeDelta(m_nDeltaMicroSecs * n);
        }
        CTimeDelta operator/(INT64 n) const 
        {
            return CTimeDelta(m_nDeltaMicroSecs / n);
        }
        CTimeDelta& operator*=(INT64 n)
        {
            m_nDeltaMicroSecs *= n;
            return *this;
        }
        CTimeDelta& operator/=(INT64 n) 
        {
            m_nDeltaMicroSecs /= n;
            return *this;
        }
        INT64 operator/(CTimeDelta Other) const 
        {
            return m_nDeltaMicroSecs / Other.m_nDeltaMicroSecs;
        }

        // Defined below because it depends on the definition of the Other classes.
        CTime operator+(CTime t) const;
        CTimeTicks operator+(CTimeTicks t) const;

        // Comparison operators.
        BOOL operator==(CTimeDelta Other) const 
        {
            return m_nDeltaMicroSecs == Other.m_nDeltaMicroSecs;
        }
        BOOL operator!=(CTimeDelta Other) const 
        {
            return m_nDeltaMicroSecs != Other.m_nDeltaMicroSecs;
        }
        BOOL operator<(CTimeDelta Other) const
        {
            return m_nDeltaMicroSecs < Other.m_nDeltaMicroSecs;
        }
        BOOL operator<=(CTimeDelta Other) const 
        {
            return m_nDeltaMicroSecs <= Other.m_nDeltaMicroSecs;
        }
        BOOL operator>(CTimeDelta Other) const
        {
            return m_nDeltaMicroSecs > Other.m_nDeltaMicroSecs;
        }
        BOOL operator>=(CTimeDelta Other) const
        {
            return m_nDeltaMicroSecs >= Other.m_nDeltaMicroSecs;
        }

    private:
        friend class CTime;
        friend class CTimeTicks;
        friend CTimeDelta operator*(INT64 n, CTimeDelta td);

        // Constructs a delta given the duration in microseconds. This is private
        // to avoid confusion by callers with an integer constructor. Use
        // FromSeconds, FromMilliseconds, etc. instead.
        explicit CTimeDelta(INT64 nDeltaUS) : m_nDeltaMicroSecs(nDeltaUS)
        {
        }

        // Delta in microseconds.
        INT64 m_nDeltaMicroSecs;
    };

    inline CTimeDelta operator*(INT64 n, CTimeDelta td)
    {
        return CTimeDelta(n * td.m_nDeltaMicroSecs);
    }

    // CTime -----------------------------------------------------------------------

    // Represents a wall clock time.
    class CTime {
    public:
        static const INT64 kMillisecondsPerSecond = 1000;
        static const INT64 kMicrosecondsPerMillisecond = 1000;
        static const INT64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond *
            kMillisecondsPerSecond;
        static const INT64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
        static const INT64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
        static const INT64 kMicrosecondsPerDay = kMicrosecondsPerHour * 24;
        static const INT64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
        static const INT64 kNanosecondsPerMicrosecond = 1000;
        static const INT64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
            kMicrosecondsPerSecond;

        // Represents an exploded time that can be formatted nicely.
        struct Exploded
        {
            INT year;          // Four digit year "2007"
            INT month;         // 1-based month (values 1 = January, etc.)
            INT day_of_week;   // 0-based day of week (0 = Sunday, etc.)
            INT day_of_month;  // 1-based day of month (1-31)
            INT hour;          // Hour within the current day (0-23)
            INT minute;        // Minute within the current hour (0-59)
            INT second;        // Second within the current minute (0-59 plus leap
            //   seconds which may take it up to 60).
            INT millisecond;   // Milliseconds within the current second (0-999)
        };

        // Contains the NULL time. Use CTime::Now() to get the current time.
        explicit CTime() : m_nUTCMicroSecs(0)
        {
        }

        // Returns true if the time object has not been initialized.
        BOOL IsNull() const 
        {
            return m_nUTCMicroSecs == 0;
        }

        // Returns the current time. Watch out, the system might adjust its clock
        // in which case time will actually go backwards. We don't guarantee that
        // times are increasing, or that two calls to Now() won't be the same.
        static CTime Now();

        // Returns the current time. Same as Now() except that this function always
        // uses system time so that there are no discrepancies between the returned
        // time and system time even on virtual environments including our test bot.
        // For timing sensitive unittests, this function should be used.
        static CTime NowFromSystemTime();

        // Converts to/from time_t in UTC and a CTime class.
        // TODO(brettw) this should be removed once everybody starts using the |CTime|
        // class.
        static CTime FromTimeT(time_t tt);
        time_t ToTimeT() const;

        // Converts time to/from a double which is the number of seconds since epoch
        // (Jan 1, 1970).  Webkit uses this format to represent time.
        static CTime FromDoubleT(DOUBLE dt);
        DOUBLE ToDoubleT() const;

        static CTime FromFileTime(FILETIME ft);
        FILETIME ToFileTime() const;

        // Converts an exploded structure representing either the local time or UTC
        // into a CTime class.
        static CTime FromUTCExploded(const Exploded& exploded) {
            return FromExploded(false, exploded);
        }
        static CTime FromLocalExploded(const Exploded& exploded) {
            return FromExploded(true, exploded);
        }

        // Converts an integer value representing CTime to a class. This is used
        // when deserializing a |CTime| structure, using a value known to be
        // compatible. It is not provided as a constructor because the integer type
        // may be unclear from the perspective of a caller.
        static CTime FromInternalValue(INT64 nMicroSecs) 
        {
            return CTime(nMicroSecs);
        }

        // For serializing, use FromInternalValue to reconstitute. Please don't use
        // this and do arithmetic on it, as it is more error prone than using the
        // provided operators.
        INT64 ToInternalValue() const 
        {
            return m_nUTCMicroSecs;
        }

        // Fills the given exploded structure with either the local time or UTC from
        // this time structure (containing UTC).
        VOID UTCExplode(Exploded* exploded) const 
        {
            return Explode(false, exploded);
        }
        VOID LocalExplode(Exploded* exploded) const 
        {
            return Explode(true, exploded);
        }

        // Rounds this time down to the nearest day in local time. It will represent
        // midnight on that day.
        CTime LocalMidnight() const;

        CTime& operator=(CTime Other) 
        {
            m_nUTCMicroSecs = Other.m_nUTCMicroSecs;
            return *this;
        }

        // Compute the difference between two times.
        CTimeDelta operator-(CTime Other) const
        {
            return CTimeDelta(m_nUTCMicroSecs - Other.m_nUTCMicroSecs);
        }

        // Modify by some time delta.
        CTime& operator+=(CTimeDelta delta)
        {
            m_nUTCMicroSecs += delta.m_nDeltaMicroSecs;
            return *this;
        }
        CTime& operator-=(CTimeDelta delta) 
        {
            m_nUTCMicroSecs -= delta.m_nDeltaMicroSecs;
            return *this;
        }

        // Return a new time modified by some delta.
        CTime operator+(CTimeDelta delta) const 
        {
            return CTime(m_nUTCMicroSecs + delta.m_nDeltaMicroSecs);
        }
        CTime operator-(CTimeDelta delta) const 
        {
            return CTime(m_nUTCMicroSecs - delta.m_nDeltaMicroSecs);
        }

        // Comparison operators
        BOOL operator==(CTime Other) const 
        {
            return m_nUTCMicroSecs == Other.m_nUTCMicroSecs;
        }
        BOOL operator!=(CTime Other) const 
        {
            return m_nUTCMicroSecs != Other.m_nUTCMicroSecs;
        }
        BOOL operator<(CTime Other) const
        {
            return m_nUTCMicroSecs < Other.m_nUTCMicroSecs;
        }
        BOOL operator<=(CTime Other) const 
        {
            return m_nUTCMicroSecs <= Other.m_nUTCMicroSecs;
        }
        BOOL operator>(CTime Other) const 
        {
            return m_nUTCMicroSecs > Other.m_nUTCMicroSecs;
        }
        BOOL operator>=(CTime Other) const 
        {
            return m_nUTCMicroSecs >= Other.m_nUTCMicroSecs;
        }

    private:
        friend class CTimeDelta;

        // Explodes the given time to either local time |bNeedLocal = true| or UTC
        // |bNeedLocal = false|.
        VOID Explode(BOOL bNeedLocal, Exploded* exploded) const;

        // Unexplodes a given time assuming the source is either local time
        // |is_local = true| or UTC |is_local = false|.
        static CTime FromExploded(BOOL bIsLocal, const Exploded& exploded);

        explicit CTime(INT64 us) : m_nUTCMicroSecs(us) 
        {
        }

        // The representation of Jan 1, 1970 UTC in microseconds since the
        // platform-dependent epoch.
        static const INT64 kTimeTToMicrosecondsOffset;

        // CTime in microseconds in UTC.
        INT64 m_nUTCMicroSecs;
    };

    // CTimeTicks ------------------------------------------------------------------

    class CTimeTicks {
    public:
        CTimeTicks() : m_nTicks(0)
        {
        }

        // Platform-dependent tick count representing "right now."
        // The resolution of this clock is ~1-15ms.  Resolution varies depending
        // on hardware/operating system configuration.
        static CTimeTicks Now();

        // Returns true if this object has not been initialized.
        BOOL IsNull() const 
        {
            return m_nTicks == 0;
        }

        // Returns the internal numeric value of the CTimeTicks object.
        INT64 ToInternalValue() const
        {
            return m_nTicks;
        }

        CTimeTicks& operator=(CTimeTicks Other)
        {
            m_nTicks = Other.m_nTicks;
            return *this;
        }

        // Compute the difference between two times.
        CTimeDelta operator-(CTimeTicks Other) const
        {
            return CTimeDelta(m_nTicks - Other.m_nTicks);
        }

        // Modify by some time delta.
        CTimeTicks& operator+=(CTimeDelta delta) 
        {
            m_nTicks += delta.m_nDeltaMicroSecs;
            return *this;
        }
        CTimeTicks& operator-=(CTimeDelta delta) 
        {
            m_nTicks -= delta.m_nDeltaMicroSecs;
            return *this;
        }

        // Return a new CTimeTicks modified by some delta.
        CTimeTicks operator+(CTimeDelta delta) const 
        {
            return CTimeTicks(m_nTicks + delta.m_nDeltaMicroSecs);
        }
        CTimeTicks operator-(CTimeDelta delta) const
        {
            return CTimeTicks(m_nTicks - delta.m_nDeltaMicroSecs);
        }

        // Comparison operators
        BOOL operator==(CTimeTicks Other) const 
        {
            return m_nTicks == Other.m_nTicks;
        }
        BOOL operator!=(CTimeTicks Other) const
        {
            return m_nTicks != Other.m_nTicks;
        }
        BOOL operator<(CTimeTicks Other) const 
        {
            return m_nTicks < Other.m_nTicks;
        }
        BOOL operator<=(CTimeTicks Other) const 
        {
            return m_nTicks <= Other.m_nTicks;
        }
        BOOL operator>(CTimeTicks Other) const 
        {
            return m_nTicks > Other.m_nTicks;
        }
        BOOL operator>=(CTimeTicks Other) const
        {
            return m_nTicks >= Other.m_nTicks;
        }

    protected:
        friend class CTimeDelta;

        // Please use Now() to create a new object. This is for internal use
        // and testing. Ticks is in microseconds.
        explicit CTimeTicks(INT64 ticks) : m_nTicks(ticks)
        {
        }

        // Tick count in microseconds.
        INT64 m_nTicks;
    };

    inline CTime CTimeDelta::operator+(CTime t) const
    {
        return CTime(t.m_nUTCMicroSecs + m_nDeltaMicroSecs);
    }

    inline CTimeTicks CTimeDelta::operator+(CTimeTicks t) const
    {
        return CTimeTicks(t.m_nTicks + m_nDeltaMicroSecs);
    }

    // Inline the CTimeDelta factory methods, for fast CTimeDelta construction.

    // static


    inline CTimeDelta CTimeDelta::FromDays(INT64 nDays)
    {
        return CTimeDelta(nDays * CTime::kMicrosecondsPerDay);
    }

    // static
    inline CTimeDelta CTimeDelta::FromHours(INT64 nHours) 
    {
        return CTimeDelta(nHours * CTime::kMicrosecondsPerHour);
    }

    // static
    inline CTimeDelta CTimeDelta::FromMinutes(INT64 nMinutes) 
    {
        return CTimeDelta(nMinutes * CTime::kMicrosecondsPerMinute);
    }

    // static
    inline CTimeDelta CTimeDelta::FromSeconds(INT64 nSecs)
    {
        return CTimeDelta(nSecs * CTime::kMicrosecondsPerSecond);
    }

    // static
    inline CTimeDelta CTimeDelta::FromMilliseconds(INT64 nMilliSecs)
    {
        return CTimeDelta(nMilliSecs * CTime::kMicrosecondsPerMillisecond);
    }

    // static
    inline CTimeDelta CTimeDelta::FromMicroseconds(INT64 nMicroSecs)
    {
        return CTimeDelta(nMicroSecs);
    }
}



namespace xBase{

    // From MSDN, FILETIME "Contains a 64-bit value representing the number of
    // 100-nanosecond intervals since January 1, 1601 (UTC)."
    inline INT64 FileTimeToMicroseconds(const FILETIME& ft)
    {
        // Need to bit_cast to fix alignment, then divide by 10 to convert
        // 100-nanoseconds to milliseconds. This only works on little-endian
        // machines.
        INT64 nMicrosSeconds = ft.dwHighDateTime;
        nMicrosSeconds = nMicrosSeconds << 32;
        nMicrosSeconds += ft.dwLowDateTime;

        return nMicrosSeconds / 10;
        //return bit_cast<INT64, FILETIME>(ft) / 10;
    }

    inline VOID MicrosecondsToFileTime(INT64 nMicroSeconds, FILETIME* ft) 
    {
        // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will
        // handle alignment problems. This only works on little-endian machines.
        nMicroSeconds *= 10;
        ft->dwLowDateTime = DWORD(nMicroSeconds & 0xFFFFFFFF);
        ft->dwHighDateTime = DWORD((nMicroSeconds >> 32) & 0xFFFFFFFF);
        //*ft = bit_cast<FILETIME, INT64>(us * 10);
    }

    inline INT64 CurrentWallclockMicroseconds()
    {
        FILETIME ft;
        ::GetSystemTimeAsFileTime(&ft);
        return FileTimeToMicroseconds(ft);
    }

    // CTime between resampling the un-granular clock for this API.  60 seconds.
    const int kMaxMillisecondsToAvoidDrift = 60 * CTime::kMillisecondsPerSecond;

    __declspec(selectany) INT64 nInitialTime = 0;
    __declspec(selectany) CTimeTicks InitialTicks;

    inline VOID InitializeClock() 
    {
        InitialTicks = CTimeTicks::Now();
        nInitialTime = CurrentWallclockMicroseconds();
    }

}

namespace xBase
{
    // The internal representation of CTime uses FILETIME, whose epoch is 1601-01-01
    // 00:00:00 UTC.  ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
    // number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
    // 1700, 1800, and 1900.
    // static
    __declspec(selectany) const INT64 CTime::kTimeTToMicrosecondsOffset = 11644473600000000I64;

    // CTimeDelta ------------------------------------------------------------------

    inline INT CTimeDelta::InDays() const 
    {
        return static_cast<INT>(m_nDeltaMicroSecs / CTime::kMicrosecondsPerDay);
    }

    inline INT CTimeDelta::InHours() const
    {
        return static_cast<INT>(m_nDeltaMicroSecs / CTime::kMicrosecondsPerHour);
    }

    inline INT CTimeDelta::InMinutes() const 
    {
        return static_cast<INT>(m_nDeltaMicroSecs / CTime::kMicrosecondsPerMinute);
    }

    inline DOUBLE CTimeDelta::InSecondsF() const
    {
        return static_cast<DOUBLE>(m_nDeltaMicroSecs) / CTime::kMicrosecondsPerSecond;
    }

    inline INT64 CTimeDelta::InSeconds() const 
    {
        return m_nDeltaMicroSecs / CTime::kMicrosecondsPerSecond;
    }

    inline DOUBLE CTimeDelta::InMillisecondsF() const
    {
        return static_cast<DOUBLE>(m_nDeltaMicroSecs) / CTime::kMicrosecondsPerMillisecond;
    }

    inline INT64 CTimeDelta::InMilliseconds() const
    {
        return m_nDeltaMicroSecs / CTime::kMicrosecondsPerMillisecond;
    }

    inline INT64 CTimeDelta::InMillisecondsRoundedUp() const
    {
        return (m_nDeltaMicroSecs + CTime::kMicrosecondsPerMillisecond - 1) /
            CTime::kMicrosecondsPerMillisecond;
    }

    inline INT64 CTimeDelta::InMicroseconds() const 
    {
        return m_nDeltaMicroSecs;
    }

    // CTime -----------------------------------------------------------------------

    // static
    inline CTime CTime::FromTimeT(time_t tt)
    {
        if (tt == 0)
            return CTime();  // Preserve 0 so we can tell it doesn't exist.
        return CTime((tt * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset);
    }

    inline time_t CTime::ToTimeT() const
    {
        if (m_nUTCMicroSecs == 0)
            return 0;  // Preserve 0 so we can tell it doesn't exist.

        return (m_nUTCMicroSecs - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond;
    }

    // static
    inline CTime CTime::FromDoubleT(DOUBLE dt) 
    {
        return CTime(static_cast<INT64>((dt *
            static_cast<DOUBLE>(kMicrosecondsPerSecond)) +
            kTimeTToMicrosecondsOffset));
    }

    inline DOUBLE CTime::ToDoubleT() const 
    {
        if (m_nUTCMicroSecs == 0)
            return 0;  // Preserve 0 so we can tell it doesn't exist.

        return (static_cast<DOUBLE>(m_nUTCMicroSecs - kTimeTToMicrosecondsOffset) /
            static_cast<DOUBLE>(kMicrosecondsPerSecond));
    }

    inline CTime CTime::LocalMidnight() const
    {
        Exploded exploded;
        LocalExplode(&exploded);
        exploded.hour = 0;
        exploded.minute = 0;
        exploded.second = 0;
        exploded.millisecond = 0;
        return FromLocalExploded(exploded);
    }

    // static
    inline CTime CTime::Now()
    {
        if (nInitialTime == 0)
            InitializeClock();

        // We implement time using the high-resolution timers so that we can get
        // timeouts which are smaller than 10-15ms.  If we just used
        // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
        //
        // To make this work, we initialize the clock (initial_time) and the
        // counter (initial_ctr).  To compute the initial time, we can check
        // the number of ticks that have elapsed, and compute the delta.
        //
        // To avoid any drift, we periodically resync the counters to the system
        // clock.
        while (true) 
        {
            CTimeTicks ticks = CTimeTicks::Now();

            // Calculate the time elapsed since we started our timer
            CTimeDelta elapsed = ticks - InitialTicks;

            // Check if enough time has elapsed that we need to resync the clock.
            if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) 
            {
                InitializeClock();
                continue;
            }

            return CTime(elapsed + CTime(nInitialTime));
        }
    }

    // static
    inline CTime CTime::NowFromSystemTime()
    {
        // Force resync.
        InitializeClock();
        return CTime(nInitialTime);
    }

    // static
    inline CTime CTime::FromFileTime(FILETIME ft) 
    {
        return CTime(FileTimeToMicroseconds(ft));
    }

    inline FILETIME CTime::ToFileTime() const 
    {
        FILETIME utc_ft;
        MicrosecondsToFileTime(m_nUTCMicroSecs, &utc_ft);
        return utc_ft;
    }

    // static
    inline CTime CTime::FromExploded(BOOL bIsLocal, const Exploded& exploded) {
        // Create the system struct representing our exploded time. It will either be
        // in local time or UTC.
        SYSTEMTIME st;
        st.wYear = static_cast<WORD>(exploded.year);
        st.wMonth = static_cast<WORD>(exploded.month);
        st.wDayOfWeek = static_cast<WORD>(exploded.day_of_week);
        st.wDay = static_cast<WORD>(exploded.day_of_month);
        st.wHour = static_cast<WORD>(exploded.hour);
        st.wMinute = static_cast<WORD>(exploded.minute);
        st.wSecond = static_cast<WORD>(exploded.second);
        st.wMilliseconds = static_cast<WORD>(exploded.millisecond);

        // Convert to FILETIME.
        FILETIME ft;
        if (!SystemTimeToFileTime(&st, &ft)) 
        {
            return CTime(0);
        }

        // Ensure that it's in UTC.
        if (bIsLocal)
        {
            FILETIME utc_ft;
            LocalFileTimeToFileTime(&ft, &utc_ft);
            return CTime(FileTimeToMicroseconds(utc_ft));
        }

        return CTime(FileTimeToMicroseconds(ft));
    }

    inline VOID CTime::Explode(BOOL bNeedLocal, Exploded* exploded) const
    {
        // FILETIME in UTC.
        FILETIME utc_ft;
        MicrosecondsToFileTime(m_nUTCMicroSecs, &utc_ft);

        // FILETIME in local time if necessary.
        BOOL bSuccess = TRUE;
        FILETIME ft;
        if (bNeedLocal)
            bSuccess = FileTimeToLocalFileTime(&utc_ft, &ft);
        else
            ft = utc_ft;

        // FILETIME in SYSTEMTIME (exploded).
        SYSTEMTIME st;
        if (!bSuccess || !FileTimeToSystemTime(&ft, &st)) 
        {
            ZeroMemory(exploded, sizeof(exploded));
            return;
        }

        exploded->year = st.wYear;
        exploded->month = st.wMonth;
        exploded->day_of_week = st.wDayOfWeek;
        exploded->day_of_month = st.wDay;
        exploded->hour = st.wHour;
        exploded->minute = st.wMinute;
        exploded->second = st.wSecond;
        exploded->millisecond = st.wMilliseconds;
    }

    // CTimeTicks ------------------------------------------------------------------
    namespace {
        // The last timeGetTime value we saw, to detect rollover.
        LARGE_INTEGER liLastSeenNow = {0};

        LARGE_INTEGER liRollOverUS = {0};

        LARGE_INTEGER liFrequency = {0};

        // Lock protecting rollover_ms and last_seen_now.
        // Note: this is a global object, and we usually avoid these. However, the time
        // code is low-level, and we don't want to use Singletons here (it would be too
        // easy to use a Singleton without even knowing it, and that may lead to many
        // gotchas). Its impact on startup time should be negligible due to low-level
        // nature of time code.
        xBase::CxLock RolloverLock;
    }  // namespace

    // static
    inline CTimeTicks CTimeTicks::Now() 
    {
        xBase::CxAutoLock locked(RolloverLock);

        if (liFrequency.QuadPart == 0)
        {
            QueryPerformanceFrequency(&liFrequency);
        }
        LARGE_INTEGER liTimeCounter;
        QueryPerformanceCounter(&liTimeCounter);
        if (liTimeCounter.QuadPart < liLastSeenNow.QuadPart)
        {
            liRollOverUS.QuadPart += (0x100000000I64);
        }

        liLastSeenNow = liTimeCounter;
        return ( CTimeTicks() + CTimeDelta( (INT64)( (liTimeCounter.QuadPart + liRollOverUS.QuadPart) * CTime::kMicrosecondsPerSecond / (double)liFrequency.QuadPart ) ) ) ;
    }

}